/*********************************************************************************
 *      Copyright:  (C) 2022 Zhang Changxing<ZhangChangxingVIP@163.com>
 *                  All rights reserved.
 *
 *       Filename:  sms_send.c
 *    Description:  This file mainly realizes the text message sending in both Chinese and English.
 *                 
 *        Version:  1.0.0(07/28/2022)
 *         Author:  Zhang Changxing <ZhangChangxingVIP@163.com>
 *      ChangeLog:  1, Release initial version on "07/28/2022  01:33:25 AM"
 *                 
 ********************************************************************************/



#include "sms_send.h"


/*---------------------------------------------------------------------------
 *   description:   It is used to send the AT command, receive and judge the return information
 *          args:   $ttyusb_ctx:        Serial port property context
 *                  $at_buf:            A buffer that holds AT instructions
 *                  $expect_buf:        The string you expect to receive
 *                  $return_buf:        The address of the buffer that receives 
 *                  the returned information
 *                  $return_buf_len:   return_buf length
 *  return value:   <0: failure,    =0: ok 
 *---------------------------------------------------------------------------*/
int send_at_cmd(ttyusb_ctx_t *ttyusb_ctx, char *at_buf, const char *expect_buf, char *return_buf, int return_buf_len)
{
    char   temp_buf[512] = {0};

    if (!at_buf || !expect_buf)
    {
        log_error("Unable to send AT commond,Invalid parameter.\n");
        return -1;
    }

    if(tty_send(ttyusb_ctx, at_buf, strlen(at_buf)) < 0)
    {
        log_error("Send AT commond failed:%s\n",strerror(errno));
        return -2;
    }
    
    usleep(10000);
    if(return_buf && return_buf_len)
    {
        if (tty_recv(ttyusb_ctx, return_buf, return_buf_len) <= 0)
        {
            log_error("Recving message failed:%s\n",strerror(errno));
            return -3;
        }
        //printf("return_buf:%s\n", return_buf);
        if (!strstr(return_buf, expect_buf))
        {
            log_error("Can't find what you expect to receive[%s]\n", expect_buf);
            return -4;
        }
    }
    else
    {
        if (tty_recv(ttyusb_ctx, temp_buf, sizeof(temp_buf)) <= 0)
        {
            log_error("Recving message failed:%s\n",strerror(errno));
            return -3;
        }
        //printf("temp_buf:%s\n", temp_buf);
        if (!strstr(temp_buf, expect_buf))
        {
            log_error("Can't find what you expect to receive[%s]\n", expect_buf);
            return -4;
        }
        
    }
    
    return 0;
}


/*---------------------------------------------------------------------------
 *   description:   Check whether the serial port is available
 *          args:   $ttyusb_ctx:        Serial port property context
 *  return value:   <0: failure,    =0: ok 
 *---------------------------------------------------------------------------*/
int check_tyy_ready(ttyusb_ctx_t *ttyusb_ctx)
{
    int send_rv = -1;

    if (!ttyusb_ctx)
    {
        log_error("[%s]Invalid argument!\n", __func__);
        return -1;
    }

    send_rv = send_at_cmd(ttyusb_ctx, "AT\r", "OK", NULL, 0);
    if (0 != send_rv)
    {
        log_error("[%s]The serial port is not ready!\n", __func__);
        return -2;
    }

    log_info("[%s]The serial port is ok!\n", __func__);
    
    return 0;
}


/*---------------------------------------------------------------------------
 *   description:   Check whether the SIM card exists
 *          args:   $ttyusb_ctx:        Serial port property context
 *  return value:   <0: failure,    =0: ok 
 *---------------------------------------------------------------------------*/
int check_sim_exist(ttyusb_ctx_t *ttyusb_ctx)
{
    int send_rv = -1;

    if (!ttyusb_ctx)
    {
        log_error("[%s]Invalid argument!\n", __func__);
        return -1;
    }

    send_rv = send_at_cmd(ttyusb_ctx, "AT+CPIN?\r", "READY", NULL, 0);
    if (send_rv < 0)
    {
        log_error("[%s]The SIM card is not exist\n", __func__);
        return -2;
    }

    log_info("[%s]The SIM card is exist!\n", __func__);
    return 0;
}


/*---------------------------------------------------------------------------
 *   description:   Check whether the SIM has been registered
 *          args:   $ttyusb_ctx:        Serial port property context
 *  return value:   <0: failure,    =0: ok 
 *---------------------------------------------------------------------------*/
int check_sim_login(ttyusb_ctx_t *ttyusb_ctx)
{
    int send_rv1 = -1;
    int send_rv2 = -1;

    if (!ttyusb_ctx)
    {
        log_error("[%s]Invalid argument!\n", __func__);
        return -1;
    }

    send_rv1 = send_at_cmd(ttyusb_ctx, "AT+CREG?\r", "0,1", NULL, 0);
    send_rv2 = send_at_cmd(ttyusb_ctx, "AT+CREG?\r", "0,3", NULL, 0);
    if (send_rv1 && send_rv2)
    {
        log_error("[%s]The SIM card does not exist!\n", __func__);
        return -2;
    }

    log_info("[%s]SIM card is exist!\n", __func__);
    return 0;
}


/*---------------------------------------------------------------------------
 *   description:   Check whether the SIM card signal is normal
 *          args:   $ttyusb_ctx:        Serial port property context
 *  return value:   <0: failure,    =0: ok 
 *---------------------------------------------------------------------------*/
int check_sim_signal(ttyusb_ctx_t *ttyusb_ctx)
{
    int     send_rv = -1;
    char    return_buf[256] = {0};
    char    separator[] = " ,";
    int     signal = -1;
    char    *token = NULL;
    int     i = 1;

    if (!ttyusb_ctx)
    {
        printf("[%s]Invalid argument!\n", __func__);
        return -1;
    }

    send_rv = send_at_cmd(ttyusb_ctx, "AT+CSQ\r", "+CSQ", return_buf, sizeof(return_buf));
    if (send_rv < 0)
    {
        printf("[%s]Not found SIM signal!\n", __func__);
        return -2;
    }

    log_debug("[%s]return_buf:%s\n", __func__, return_buf);

    #if 1
   
    token = strtok(return_buf, separator);
    while (token != NULL)
    {
        ++i;
        token = strtok(NULL, separator);
        log_debug("i: %d \ntoken:%s\n", i , token);

        if(2 == i)
        {
            signal = atoi(token);
            if ((signal < 8) || (signal > 31))
            {
                log_error("[%s]The signal1 value is: %d, is not normal!\n", __func__, signal);
                return -3;
            }
            else
            {
                log_info("[%s]The signal1 value is: %d, normal!\n", __func__, signal);
                break;
            }
        }

    }
    #endif

    return 0;
}


/*---------------------------------------------------------------------------
 *   description:   Check whether the serial port and SIM are ready
 *          args:   $ttyusb_ctx:        Serial port property context
 *  return value:   <0: failure,    =0: ok 
 *---------------------------------------------------------------------------*/
int check_all_ready(ttyusb_ctx_t *ttyusb_ctx)
{
    //Ensure that the serial port is available
    if (check_tyy_ready(ttyusb_ctx) < 0)
        return -1;
    log_info("[%s]tyy is ok\n", __func__);

    //If the serial port can communicate, the SIM card can be detected
    if (check_sim_exist(ttyusb_ctx) < 0)
        return -2;
    log_info("[%s]SIM is exist!\n", __func__);

    //Check whether the SIM card is registered
    if (check_sim_login(ttyusb_ctx) < 0)
        return -3;
    log_info("[%s]SIM is login!\n", __func__);

    //Check the SIM card signal
    if (check_sim_signal(ttyusb_ctx) < 0)
        return -4;
    log_info("[%s]SIM signal is ok!\n", __func__);

    log_info("[%s]SIM and tty are ready!\n", __func__);
    return 0;
}


/*---------------------------------------------------------------------------
 *   description:   Check whether the serial port and SIM are ready
 *          args:   $ttyusb_ctx:    Serial port property context
 *                  $center_buf     Store the obtained center number
 *  return value:   <0: failure,    =0: ok 
 *---------------------------------------------------------------------------*/
int get_center_number(ttyusb_ctx_t *ttyusb_ctx, char *center_buf)
{
    int     send_rv = -1;
    char    return_buf[256] = {0};
    char    separator[] = "\"";
    char    *token = NULL;
    int     i = 1;

    if ((!ttyusb_ctx) || (!center_buf))
    {
        log_error("[%s]Invalid argument!\n", __func__);
        return -1;
    }

    #if 1
    send_rv = send_at_cmd(ttyusb_ctx, "AT+CSCA?\r", "+CSCA", return_buf, sizeof(return_buf));
    if (send_rv < 0)
    {
        log_error("[%s]Not found center number!\n", __func__);
        return -2;
    }

    token = strtok(return_buf, separator);
    while (token != NULL)
    {
        ++i;
        token = strtok(NULL, separator);
        log_debug("[%s]i: %d \ntoken:%s\n", __func__, i , token);
        if(2 == i)
        {
            strncpy(center_buf, token, strlen(token));
            break;
        }

    }
    #endif

    printf("[%s]The center number:%s\n", __func__, center_buf);
    return 0;
}


/*---------------------------------------------------------------------------
 *   description:   The Text format is used to send short messages
 *          args:   $ttyusb_ctx:    Serial port property context
 *                  $phone_buf      Store the obtained target number
 *                  $sms_buf        Information to be sent
 *  return value:   <0: failure,    =0: ok 
 *---------------------------------------------------------------------------*/
int send_text_sms(ttyusb_ctx_t *ttyusb_ctx, char *phone_buf, char *sms_buf)
{
    char    temp_buf[256] = {0};

    if (!ttyusb_ctx || !phone_buf || !sms_buf)
    {
        log_error("[%s]Invalid argument!\n", __func__);
        return -1;
    }

    if (send_at_cmd(ttyusb_ctx, "AT+CMGF=1\r", "OK", NULL, 0))
    {
        log_error("[%s]Send at command [AT+CMGF=1] to tty failure!\n", __func__);
        return -2;
    }

    printf("[%s]Send at command [AT+CMGF=1] to tty successfully!\n\n\n", __func__);
    sprintf(temp_buf, "AT+CMGS=\"%s\"\r", phone_buf);


    if (send_at_cmd(ttyusb_ctx, temp_buf, ">", NULL, 0))
    {
        log_error("[%s]Receive > failure!\n", __func__);
        return -3;
    }

    printf("[%s]Recv the '>' ok!\n", __func__);
    strcat(sms_buf, "\x1a");

    if (send_at_cmd(ttyusb_ctx, sms_buf, "OK", NULL, 0))
    {
        log_error("[%s]Failed to send SMS messages!\n", __func__);
        return -4;
    }

    log_info("[%s]Successed to send SMS messages!\n", __func__);

    return 0;
}


/*---------------------------------------------------------------------------
 *   description:   Send short messages in PDU format
 *          args:   $ttyusb_ctx:    Serial port property context
 *                  $phone_buf      Store the obtained target number
 *                  $sms_buf        Information to be sent
 *  return value:   <0: failure,    =0: ok 
 *---------------------------------------------------------------------------*/
int send_pdu_sms(ttyusb_ctx_t *ttyusb_ctx, char *phone_buf, char *sms_buf)
{
    char    center_buf[256] = {0};
    char    pdu_buf[512] = {0};
    char    at_buf[256] = {0};
    int     cmgs_length = 0;

    if (!ttyusb_ctx || !phone_buf || !sms_buf)
    {
        log_error("[%s]Invalid argument!\n", __func__);
        return -1;
    }

    if (get_center_number(ttyusb_ctx, center_buf) < 0)
    {
        log_error("[%s]Get center number failure!\n", __func__);
        return -2;
    }

    if (pdu_packet(center_buf, phone_buf, sms_buf, pdu_buf, &cmgs_length) < 0)
    {
        log_error("[%s]Failed to package SMS messages into PDU format\n", __func__);
        return -3;
    }

    if (send_at_cmd(ttyusb_ctx, "AT+CMGF=0\r", "OK", NULL,  0) < 0)
    {
        log_error("[%s]Send at command [AT+CMGF=0\r] failure!\n", __func__);
        return -4;
    }

    sprintf(at_buf, "AT+CMGS=%d\r", cmgs_length);
    if (send_at_cmd(ttyusb_ctx, at_buf, ">", NULL,  0) < 0)
    {
        log_error("[%s]Send at command [AT+CMGS=%d\r] failure!\n", __func__, cmgs_length);
        return -5;
    }

    strcat(pdu_buf,"\x1a");
    log_info("[%s] pdu_buf = %s\n",__func__ , pdu_buf);

    if (send_at_cmd(ttyusb_ctx, pdu_buf, "OK", NULL,  0))
    {
        log_error("[%s]Send pud sms failure!\n", __func__);
        return -6;
    }
    
    log_info("[%s]Send pud sms successfully!\n", __func__);
    
    return 0;
}